#include "socketwork.h"
#include <QFileInfo>
#include <QThread>
#include "utils.h"
#include "MessageErrorException.h"

SocketWork::SocketWork(qintptr desc_ptr, QObject *parent) : QObject(parent), m_desc(desc_ptr)
{
    m_socket = new QTcpSocket(this);

    if (!m_socket->setSocketDescriptor(m_desc))
    {
        throw -1;
    }

    connect(m_socket, &QTcpSocket::disconnected, this, [=]() { emit disconnect_socket_signal(m_desc); });
    connect(m_socket, &QTcpSocket::readyRead, this, &SocketWork::receive_data_slot);
}

void SocketWork::Update_IP_slot(QString ip)
{
    localIP = ip;
}

void SocketWork::send_data_slot(qintptr desc_ptr, const QByteArray &data)
{
    if (m_desc == desc_ptr)
    {
        m_socket->write(data);
        m_socket->flush();
    }
}

void SocketWork::send_Message_slot(qintptr desc_ptr, QString command)
{
    QByteArray send_bytes;

    QByteArray command_bytes = command.toUtf8();

    QByteArray header_bytes;

    header_bytes.append(char(0x00));
    header_bytes.append(char(0xff));
    header_bytes.append(char(0x0f));
    header_bytes.append(char(0x00));

    QByteArray total_length_bytes = Number2Bytes<int>(command_bytes.length() + MSG_TYPE_LENGTH + MSG_STREAM_LENGTH);
    QByteArray type_bytes = Number2Bytes<int>(ServerMsgType::ServerSendCommand);
    QByteArray command_length_bytes = Number2Bytes<int>(command_bytes.length());

    send_bytes.append(header_bytes);
    send_bytes.append(total_length_bytes);
    send_bytes.append(type_bytes);
    send_bytes.append(command_length_bytes);
    send_bytes.append(command_bytes);

    send_data_slot(desc_ptr, send_bytes);
}

void SocketWork::send_file_slot(qintptr desc_ptr, QString path)
{
    QByteArray send_bytes;

    QByteArray header_bytes;

    header_bytes.append(char(0x00));
    header_bytes.append(char(0xff));
    header_bytes.append(char(0x0f));
    header_bytes.append(char(0x00));

    QFileInfo file_info(path);
    QByteArray file_name_bytes = file_info.fileName().toUtf8();

    QByteArray file_bytes;

    QFile file(path);
    if (!file.open(QIODevice::ReadOnly))
    {
        return;
    }

    file_bytes = file.readAll();
    file.close();

    QByteArray total_length_bytes = Number2Bytes<int>(MSG_TYPE_LENGTH + MSG_STREAM_LENGTH + file_name_bytes.length() +
                                                      MSG_STREAM_LENGTH + file_bytes.length());
    QByteArray type_bytes = Number2Bytes<int>(ServerMsgType::ServerSendFile);

    QByteArray file_name_length_bytes = Number2Bytes<int>(file_name_bytes.length());

    QByteArray file_length_bytes = Number2Bytes<int>(file_bytes.length());

    send_bytes.append(header_bytes);
    send_bytes.append(total_length_bytes);
    send_bytes.append(type_bytes);
    send_bytes.append(file_name_length_bytes);
    send_bytes.append(file_name_bytes);
    send_bytes.append(file_length_bytes);
    send_bytes.append(file_bytes);

    send_data_slot(desc_ptr, send_bytes);

    qDebug() << "sendFile ...";
}

void SocketWork::send_pic_slot(qintptr desc_ptr, QString path)
{
    QByteArray send_bytes;

    QByteArray header_bytes;

    header_bytes.append(char(0x00));
    header_bytes.append(char(0xff));
    header_bytes.append(char(0x0f));
    header_bytes.append(char(0x00));

    QFileInfo file_info(path);
    QByteArray file_name_bytes = file_info.fileName().toLocal8Bit();

    QByteArray file_bytes;

    QFile file(path);
    if (!file.open(QIODevice::ReadOnly))
    {
        return;
    }

    file_bytes = file.readAll();
    file.close();

    QByteArray total_length_bytes = Number2Bytes<int>(MSG_TYPE_LENGTH + MSG_STREAM_LENGTH + file_name_bytes.length() +
                                                      MSG_STREAM_LENGTH + file_bytes.length());
    QByteArray type_bytes = Number2Bytes<int>(ServerMsgType::ServerSendFile);

    QByteArray file_name_length_bytes = Number2Bytes<int>(file_name_bytes.length());

    QByteArray file_length_bytes = Number2Bytes<int>(file_bytes.length());

    send_bytes.append(header_bytes);
    send_bytes.append(total_length_bytes);
    send_bytes.append(type_bytes);
    send_bytes.append(file_name_length_bytes);
    send_bytes.append(file_name_bytes);
    send_bytes.append(file_length_bytes);
    send_bytes.append(file_bytes);

    send_data_slot(desc_ptr, send_bytes);
}

void SocketWork::receive_data_slot()
{
    QByteArray data = m_socket->readAll();
    receive_bytes.append(data);

    try
    {
        const int index = unpack_receive_data();
        if (index > 0)
        {
            receive_bytes.remove(0, index);
        }
    }
    catch (MessageErrorException &)
    {
        receive_bytes.clear();
        emit update_textBrowser_signal("Receive Message Header error, auto disconnect socket");
        disconnect_socket_slot(m_desc);
    }
}

void SocketWork::disconnect_socket_slot(qintptr desc_ptr)
{
    if (m_desc == desc_ptr)
    {
        m_socket->disconnectFromHost();
        if (m_socket->state() != QAbstractSocket::UnconnectedState)
        {
            m_socket->waitForDisconnected();
        }
    }
}

int SocketWork::unpack_receive_data()
{
    int index = 0;

    while (true)
    {
        if (index + MSG_HEADER_LENGTH + MSG_TOTAL_LENGTH + MSG_TYPE_LENGTH >= receive_bytes.length())
        {
            break;
        }
        else
        {
            QByteArray msg_header = receive_bytes.mid(index, MSG_HEADER_LENGTH);

            if (static_cast<unsigned char>(msg_header.at(0)) != 0x00 ||
                static_cast<unsigned char>(msg_header.at(1)) != 0xff ||
                static_cast<unsigned char>(msg_header.at(2)) != 0x0f ||
                static_cast<unsigned char>(msg_header.at(3)) != 0x00)
            {
                throw MessageErrorException(-1);
            }

            int msg_length = Bytes2Number<int>(receive_bytes.mid(index + MSG_HEADER_LENGTH, MSG_TOTAL_LENGTH));

            if (msg_length + index + MSG_HEADER_LENGTH + MSG_TOTAL_LENGTH > receive_bytes.length())
            {
                break;
            }

            ClientMsgType msg_type = ClientMsgType(
                Bytes2Number<int>(receive_bytes.mid(index + MSG_HEADER_LENGTH + MSG_TOTAL_LENGTH, MSG_TYPE_LENGTH)));

            QByteArray msg_data = receive_bytes.mid(index + MSG_HEADER_LENGTH + MSG_TOTAL_LENGTH + MSG_TYPE_LENGTH,
                                                    msg_length - MSG_TYPE_LENGTH);

            index += msg_length + MSG_HEADER_LENGTH + MSG_TOTAL_LENGTH;

            if (msg_type == ClientSendCommand)
            {
                handle_command_message(msg_data);
            }
            else if(msg_type == ClientSendHeartbeat)
            {
                qDebug() << "Heart beat";
            }
            else if(msg_type == ClientSendPreview)
            {
                handle_preview_message(msg_data);
            }
            else
            {
                throw MessageErrorException(-2);
            }
        }
    }

    return index;
}
void SocketWork::handle_preview_message(const QByteArray &bytes)
{
    qDebug() << bytes.length();
    int message_length = Bytes2Number<int>(bytes.mid(0, 4));

    QByteArray message_bytes = bytes.mid(4, message_length);
    QPixmap pixmap;

    if (!pixmap.loadFromData(message_bytes))
    {
        return;
    }

    emit preview_image_signal(pixmap.copy());
}
void SocketWork::handle_command_message(const QByteArray &bytes)
{
    int message_length = Bytes2Number<int>(bytes.mid(0, 4));
    QString message_body = QString(bytes.mid(4, message_length));

    emit update_textBrowser_signal(message_body);

}
